#include "ssd_wrftl.h"

int WRFTL_Window_Size = 0; //WRFTL优先置换区大小
int WRFTL_maxentry = 0;
double WRFTL_Tau = 0.3; //通过Tau调控window_size比例
Node *WRFTL_Head=NULL;

void WRFTL_Scheme(unsigned int *pageno,int *req_size,int operation)
{
    int blkno=(*pageno),cnt=(*req_size);
    int ghost_min=-1,pos=-1;   //zan shi mei yong 
    Node *Temp;
    //初始化
    if (init_flag==0)
    {
        // CMT value size is 32KB include entry(512 in 2Kpage)
        // 这里real_arr当作WCMT WCMT 40KB －> 10240
        // 把ghost_arr当作RCMT
        // ghost_arr is 24KB ,6144 entries

        MAP_REAL_MAX_ENTRIES=3276;
        real_arr=(int *)malloc(sizeof(int)*MAP_REAL_MAX_ENTRIES);
        MAP_GHOST_MAX_ENTRIES=820;
        ghost_arr=(int *)malloc(sizeof(int)*MAP_GHOST_MAX_ENTRIES);
        //WCMT的优先置换区
        WRFTL_Window_Size=(int)MAP_REAL_MAX_ENTRIES*WRFTL_Tau;
        WRFTL_Head=CreateList();
        WRFTL_init_arr();
        init_flag=1;
    }
    
    /*******************正式进入仿真运行******************/
    operation_time++; //师兄是放到每个操作里面去，但是直接外面统计，应当更方便
    //req_entry hit in WCMT
    if(opagemap[blkno].map_status==MAP_REAL){
        if(ListLength(WRFTL_Head)!=MAP_REAL_NUM_ENTRIES){ //debug
            printf("before WRFTL hit in WCMT error, ListLength is %d, real_arr size is %d\n", ListLength(WRFTL_Head),MAP_REAL_NUM_ENTRIES);
            assert(0);
        }
        WRFTL_Hit_WCMT(blkno, operation);
        if(ListLength(WRFTL_Head)!=MAP_REAL_NUM_ENTRIES){ //debug
            printf("after WRFTL hit in WCMT error, ListLength is %d, real_arr size is %d\n", ListLength(WRFTL_Head),MAP_REAL_NUM_ENTRIES);
            assert(0);
        }
        //数据统计
        rqst_cnt++;
        cache_scmt_hit++;
        blkno++;
    }
    // req_entry hit in RCMT
    else if (opagemap[blkno].map_status==MAP_GHOST){
        //write
        if(operation==0){
            WRFTL_Move_RCMT2WCMT(blkno, operation);
            //debug
            if(ListLength(WRFTL_Head)!=MAP_REAL_NUM_ENTRIES){
                printf(" after WRFTL_Move_RCMT2WCMT error,ListLength is %d,real_arr size is %d\n",ListLength(WRFTL_Head),MAP_REAL_NUM_ENTRIES);
                assert(0);
            }
        }
        //read
        else{
            WRFTL_Move_RCMT2MRU(blkno, operation);

        }
        //数据统计
        rqst_cnt++;
        cache_slcmt_hit++;
        blkno++;
    }
    // req_entry miss in CMT
    else{
        //预取
        if(operation==0)
            WRFTL_Write_Pre_Load(&blkno, &cnt);
        else
            WRFTL_Read_Pre_Load(&blkno, &cnt);
    }
    (*pageno)=blkno,(*req_size)=cnt;
}


void WRFTL_init_arr()
{
    int i;
    for( i = 0; i < MAP_REAL_MAX_ENTRIES; i++) {
        real_arr[i] = -1;
    }
    for( i= 0; i < MAP_GHOST_MAX_ENTRIES; i++) {
        ghost_arr[i] = -1;
    }
    MAP_REAL_NUM_ENTRIES = 0;
    MAP_GHOST_NUM_ENTRIES = 0;
}

/*********************
* 请求命中WCMT
*/
void WRFTL_Hit_WCMT(int blkno, int operation)
{
    Node *temp;
    opagemap[blkno].map_status=MAP_REAL;
    opagemap[blkno].map_age=operation_time;

    //操作链表的LRU
    temp=SearchLPNInList(blkno, WRFTL_Head);
    if(temp==NULL){
        printf("error in ADFTL_Hit_R_CMT,can not find blkno %d in List\n",blkno);
        assert(0);
    }
    else{
        //move node
        InsertNodeInListMRU(temp,WRFTL_Head);
    }
    if(operation==0){
        write_count++;
        opagemap[blkno].update = 1;
    }
    else
        read_count++;

    send_flash_request(blkno*4, 4, operation, 1);
}

/**************************
* 读请求命中RMCT
* 映射信息迁移至RCMT的MRU
*/
void WRFTL_Move_RCMT2MRU(int blkno, int operation)
{
    //ghost_arr不变，map_age改变就相当于是迁移至MRU
    opagemap[blkno].map_age=operation_time;

    if(operation==0){
        write_count++;
        opagemap[blkno].update = 1;
        printf("write operation happend in RCMT, LPN=%d\n",blkno);
        assert(0);
    }
    else
        read_count++;
    //ghost_arr不进行移动操作
    send_flash_request(blkno*4, 4, operation, 1);
}

/************************
* 写请求命中RCMT
* 将映射信息从RCMT中迁移至WCMT的MRU位置
*/
void WRFTL_Move_RCMT2WCMT(int blkno, int operation)
{
    int free_pos=-1;
    int r_pos=-1;
    WRFTL_WCMT_Is_Full();
    //从RCMT中剔除
    r_pos=search_table(ghost_arr, MAP_GHOST_MAX_ENTRIES, blkno);
    if(r_pos==-1){
        printf("can not find blkno :%d in ghost_arr\n",blkno);
        assert(0);
    }
    ghost_arr[r_pos]=-1;
    MAP_GHOST_NUM_ENTRIES--;
    //加入WCMT中
    free_pos=find_free_pos(real_arr, MAP_REAL_MAX_ENTRIES);
    if(free_pos==-1){
        printf("can not find free_pos in real_arr\n");
        assert(0);
    }
    real_arr[free_pos]=blkno;
    opagemap[blkno].map_status=MAP_REAL;
    opagemap[blkno].map_age=operation_time;
    //应只有写操作
    if(operation==0){
        write_count++;
        opagemap[blkno].update = 1;
    }
    else{
        read_count++;
        printf("read operation happend in RCMT2WCMT, LPN=%d\n",blkno);
        assert(0);
    }
    //链表操作
    AddNewLPNInMRU(blkno, WRFTL_Head);
    MAP_REAL_NUM_ENTRIES++;
    if(MAP_REAL_NUM_ENTRIES>MAP_REAL_MAX_ENTRIES){
        printf("real_arr overflow (WRFTL_Move_RCMT2WCMT) lpn=%d\n",blkno);
        assert(0);
    }
    send_flash_request(blkno*4, 4, operation, 1);
}

/************************
* 批量预取读写
* 读预取到RCMT
* 写预取到WCMT
* 读写都按照预取大小进行预取
*/
void WRFTL_Write_Pre_Load(int *pageno, int *req_size)
{
    int blkno=(*pageno),cnt=(*req_size);
    int pos=-1,free_pos=-1;
    int temp_num=0;
    int indexofarr=0;
    Node *temp;

    flash_hit++;  // q:ymb flash_hit 是什么？
    send_flash_request(((blkno-page_num_for_2nd_map_table)/MAP_ENTRIES_PER_PAGE)*4, 4, 1, 2);
    // 对于写请求，不采取预取策略
    for(indexofarr =0; (cnt+1>0);indexofarr++)//NUM_ENTRIES_PER_TIME在这里表示一次加载多个映射表信息
    {
        WRFTL_WCMT_Is_Full();
        
        // 若是超过了此翻译页的范围，则读取下一个翻译页
        if(((blkno-page_num_for_2nd_map_table)%MAP_ENTRIES_PER_PAGE) ==0 ){
            flash_hit++; 
            send_flash_request((((blkno-page_num_for_2nd_map_table)/MAP_ENTRIES_PER_PAGE)+1)*4, 4, 1, 2);
        }
        if(not_in_cache(blkno)==0){   // not in cache
            //映射信息加载
            opagemap[blkno].map_status=MAP_REAL;
            opagemap[blkno].map_age=operation_time;
            opagemap[blkno].update=1;
            operation_time++;
            MAP_REAL_NUM_ENTRIES++;
            cnt--;
            AddNewLPNInMRU(blkno, WRFTL_Head);
            free_pos=find_free_pos(real_arr, MAP_REAL_MAX_ENTRIES);
            if(free_pos==-1){
                printf("can not find free_pos in real_arr\n");
                assert(0);
            }
            real_arr[free_pos]=blkno;
            //对请求进行处理
            write_count++;
    
            send_flash_request(blkno*4, 4, 0, 1);
            blkno++;
            rqst_cnt++;
        }
        else if(not_in_cache(blkno)==1){  // in real arr
            WRFTL_Hit_WCMT(blkno, 0);
            cache_scmt_hit++;
            cnt--;
            operation_time++;
            blkno++;
            rqst_cnt++;
            write_count++;
        }  
        else{  // in ghost arr
            WRFTL_Move_RCMT2WCMT(blkno, 0);
            cache_slcmt_hit++;
            cnt--;
            operation_time++;
            blkno++;
            rqst_cnt++;
            write_count++;
        }
        //debug
        if(MAP_REAL_NUM_ENTRIES > MAP_REAL_MAX_ENTRIES){
            printf("The WCMT is overflow\n");
            assert(0);
        }
    }
    *req_size=cnt;
    *pageno=blkno;
}

void WRFTL_Read_Pre_Load(int *pageno, int *req_size)
{
    int blkno=(*pageno),cnt=(*req_size);
    int pos=-1,free_pos=-1;
    int temp_num=0;
    int indexofarr=0;
    Node *temp;

    //RCMT 预取
    flash_hit++;  // q:ymb flash_hit 是什么？
    send_flash_request(((blkno-page_num_for_2nd_map_table)/MAP_ENTRIES_PER_PAGE)*4, 4, 1, 2);;
    // 读取采用预取操作，取MAX{cnt,NUM_ENTRIES_PER_TIME} 
    //for(indexofarr =0; (cnt+1>0) || indexofarr < NUM_ENTRIES_PER_TIME;indexofarr++)//NUM_ENTRIES_PER_TIME在这里表示一次加载4个映射表信息
    for(indexofarr =0; (cnt+1>0) || indexofarr < NUM_ENTRIES_PER_TIME; indexofarr++)
    {
        WRFTL_RCMT_Is_Full(0);
        if((cnt+1)>0){
            // 若是超过了此翻译页的范围，则读取下一个翻译页
            if(((blkno-page_num_for_2nd_map_table)%MAP_ENTRIES_PER_PAGE) ==0 ) {
                flash_hit++; 
                send_flash_request((((blkno-page_num_for_2nd_map_table)/MAP_ENTRIES_PER_PAGE)+1)*4, 4, 1, 2);
            }
            if(not_in_cache(blkno) == 0){
                //预取映射信息
                opagemap[blkno].map_status=MAP_GHOST;
                opagemap[blkno].map_age=operation_time;
                opagemap[blkno].update=0;
                MAP_GHOST_NUM_ENTRIES++;
                // 如果是取MIN{cnt,NUM_ENTRIES_PER_TIME}，直接cnt--会有问题，会出现cnt>NUM_..时，少一次

                // free_pos=find_free_pos(ghost_arr, MAP_GHOST_MAX_ENTRIES);
                free_pos=find_free_pos(ghost_arr, MAP_GHOST_MAX_ENTRIES);
                if(free_pos==-1){
                    printf("can not find free_pos in real_arr\n");
                    assert(0);
                }
                ghost_arr[free_pos]=blkno;
                read_count++;
                send_flash_request(blkno*4, 4, 1, 1);
            }
            else if(not_in_cache(blkno) == 1){   // in real arr
                WRFTL_Hit_WCMT(blkno, 1);
                cache_scmt_hit++;
            }
            else{   // in ghost arr
                WRFTL_Move_RCMT2MRU(blkno, 1);
                cache_slcmt_hit++;
            }
            cnt--;
            operation_time++;
            blkno++;
            rqst_cnt++;
            //debug
            if(MAP_GHOST_NUM_ENTRIES > MAP_GHOST_MAX_ENTRIES){
                printf("The RCMT is overflow\n");
                assert(0);
            }
        }
        else{
            // 若是超过了此翻译页的范围，则读取下一个翻译页
            if(((blkno-page_num_for_2nd_map_table)%MAP_ENTRIES_PER_PAGE) ==0 ) {
                flash_hit++; 
                send_flash_request((((blkno-page_num_for_2nd_map_table)/MAP_ENTRIES_PER_PAGE)+1)*4, 4, 1, 2);
            }
            if(not_in_cache(blkno) == 0){
                //预取映射信息
                opagemap[blkno].map_status=MAP_GHOST;
                opagemap[blkno].map_age=operation_time;
                opagemap[blkno].update=0;
                operation_time++;
                MAP_GHOST_NUM_ENTRIES++;

                // free_pos=find_free_pos(ghost_arr, MAP_GHOST_MAX_ENTRIES);
                free_pos=find_free_pos(ghost_arr, MAP_GHOST_MAX_ENTRIES);
                if(free_pos==-1){
                    printf("can not find free_pos in real_arr\n");
                    assert(0);
                }
                ghost_arr[free_pos]=blkno;
                //read_count++;
                //由于预取
                //send_flash_request(blkno*4, 4, 1, 1);
                blkno++;
                //rqst_cnt++;
            }
        }
        
    }
    *req_size=cnt;
    *pageno=blkno;
}
/******************************
* 加载单个写请求到WCMT
*/
void WRFTL_Load_Entry2WCMT(int blkno, int operation)
{
    int free_pos=-1;
    flash_hit++;
    //read MVPN page
    send_flash_request(((blkno-page_num_for_2nd_map_table)/MAP_ENTRIES_PER_PAGE)*4, 4, 1, 2);;   // read from 2nd mapping table
    opagemap[blkno].map_status=MAP_REAL;
    opagemap[blkno].map_age=operation_time;
    free_pos=find_free_pos(real_arr, MAP_REAL_MAX_ENTRIES);
    if(free_pos==-1){
        printf("can not find free pos in real_arr\n");
        assert(0);
    }
    real_arr[free_pos]=blkno;
    //链表操作
    AddNewLPNInMRU(blkno, WRFTL_Head);
    MAP_REAL_NUM_ENTRIES++;
    //write  data page
    if(operation==0){
        write_count++;
        opagemap[blkno].update = 1;
    }
    else
        read_count++;

    send_flash_request(blkno*4, 4, operation, 1);

    // debug test
    if(opagemap[blkno].map_status!=MAP_REAL){
        printf("not set opagemap flag\n");
        assert(0);
    }
    if(search_table(real_arr,MAP_REAL_MAX_ENTRIES,blkno)==-1){
        printf("not play lpn-entry:%d into CMT\n",blkno);
        assert(0);
    }

    if(SearchLPNInList(blkno,WRFTL_Head)==NULL){
    printf("not Add blkno %d into List\n",blkno);
    assert(0);
    }

    if(ListLength(WRFTL_Head)!=MAP_REAL_NUM_ENTRIES){
    printf("List Length is %d and real_arr num is %d\n",ListLength(WRFTL_Head),MAP_REAL_NUM_ENTRIES);
    assert(0);
    }

}
/**********************************
    * 加载耽搁读请求到RCMT
    */
void WRFTL_Load_Entry2RCMT(int blkno, int operation)
{
    int free_pos=-1;
    flash_hit++;
    // read MVPN page
    send_flash_request(((blkno-page_num_for_2nd_map_table)/MAP_ENTRIES_PER_PAGE)*4, 4, 1, 2);  // read from 2nd mapping table
    opagemap[blkno].map_status = MAP_GHOST;

    opagemap[blkno].map_age=operation_time;
    free_pos=find_free_pos(ghost_arr,MAP_GHOST_MAX_ENTRIES);
    if(free_pos==-1){
        printf("can not find free pos in ghost_arr\n");
        assert(0);
    }
    ghost_arr[free_pos]=blkno;
    MAP_GHOST_NUM_ENTRIES++;
    // read data page
    if(operation==0){
        write_count++;
        opagemap[blkno].update = 1;
    }
    else
        read_count++;

    send_flash_request(blkno*4, 4, operation, 1);

    // debug test
    if(opagemap[blkno].map_status!=MAP_GHOST){
        printf("not set opagemap flag\n");
        assert(0);
    }
    if(search_table(ghost_arr,MAP_GHOST_MAX_ENTRIES,blkno)==-1){
        printf("not play lpn-entry:%d into CMT\n",blkno);
        assert(0);
    }
}

/**********************************
    * 对WCMT进行是否满对判断
    * flag表示是否是预取的判断
    * flag＝1表示预取，需要判断空间是否小于预取个数个
    */
void WRFTL_WCMT_Is_Full()
{
    //判断是否满
    if(MAP_REAL_NUM_ENTRIES-MAP_REAL_MAX_ENTRIES == 0){
        WRFTL_Remove_Entry_In_WCMT();
    }
}

/********************************
* 对WCMT映射信息剔除的封装k
*/
void WRFTL_Remove_Entry_In_WCMT()
{
    int Victim_pos=-1, free_pos=-1, curr_lpn;
    int temp_num = 0;
    int indexold = 0;
    Node *Temp;

    Victim_pos=WRFTL_Find_Victim_In_WCMT();  //此函数实现优先置换区干净页的优先剔除
    curr_lpn=real_arr[Victim_pos];

    if(opagemap[curr_lpn].update!=0){
        //表明优先置换区没有干净页，选择脏页，聚簇剔除
        //先将受害页剔除，之后与同簇数据一同回写
        opagemap[curr_lpn].map_status=MAP_INVALID;
        opagemap[curr_lpn].map_age=0;
        opagemap[curr_lpn].update=0;
        real_arr[Victim_pos]=-1;
        Temp=DeleteLRUInList(WRFTL_Head);
        if(Temp->lpn_num!=curr_lpn){
            printf("delete lru arr Temp->lpn %d not equal curr-lpn %d\n",Temp->lpn_num,curr_lpn);
            assert(0);
        }
        MAP_REAL_NUM_ENTRIES--;
        //整簇回写，数据统计
        //用WRFTL_maxentry代表待剔除的簇
        WRFTL_maxentry=(curr_lpn-page_num_for_2nd_map_table)/MAP_ENTRIES_PER_PAGE;
        send_flash_request(WRFTL_maxentry*4,4,1,2);
        send_flash_request(WRFTL_maxentry*4,4,0,2);

        //real_arr数组里面存的是lpn,将翻译页关联的映射项全部置为干净
        for(indexold = 0;indexold < MAP_REAL_MAX_ENTRIES; indexold++){
            if(((real_arr[indexold]-page_num_for_2nd_map_table)/MAP_ENTRIES_PER_PAGE) == WRFTL_maxentry){
                opagemap[real_arr[indexold]].update = 0;
            }
        }
    }
    //仅干净页剔除，无需回写操作
    else{
        opagemap[curr_lpn].map_status=MAP_INVALID;
        opagemap[curr_lpn].map_age=0;
        opagemap[curr_lpn].update=0;
        real_arr[Victim_pos]=-1;
        //链表操作，删除被置换节点
        Temp=SearchLPNInList(curr_lpn, WRFTL_Head);
        DeleteNodeInList(Temp, WRFTL_Head);
        if(Temp->lpn_num!=curr_lpn){
        printf("delete lru arr Temp->lpn %d not equal curr-lpn %d\n",Temp->lpn_num,curr_lpn);
        assert(0);
        }
        MAP_REAL_NUM_ENTRIES--;
    }
}


/********************************
* 对RCMT进行判断是否满
* flag与WCMT功能一致
*/
void WRFTL_RCMT_Is_Full()
{
    int ghost_min=-1, pos=-1;
    int temp_num=0;
    if(MAP_GHOST_NUM_ENTRIES-MAP_GHOST_MAX_ENTRIES == 0){
        ghost_min=find_min_ghost_entry();
        if(opagemap[ghost_min].update ==1){
            printf("RCMT have dirty entry\n");
            assert(0);
        }
        opagemap[ghost_min].map_status=MAP_INVALID;
        opagemap[ghost_min].map_age=0;

        //evict one entry from ghost cache 
        MAP_GHOST_NUM_ENTRIES--;
        pos=search_table(ghost_arr,MAP_GHOST_MAX_ENTRIES,ghost_min);
        if(pos==-1){
            printf("can not find ghost_min:%d  in ghost_arr\n",ghost_min);
            assert(0);
        }
        ghost_arr[pos]=-1;
    }
    
}


/***********************************
    * 通过双链表，在WCMT中找到受害页
    */
int WRFTL_Find_Victim_In_WCMT()
{
    Node *Temp;
    int i,pos_index,Victim_index,curr_lpn,clean_flag=0;
    //  从尾部进行扫描,优先找到干净项进行删除
    Temp=WRFTL_Head;
    for(i=0;i<WRFTL_Window_Size;i++){
        Temp=Temp->pre;
        curr_lpn=Temp->lpn_num;
        if(opagemap[curr_lpn].update==0 && opagemap[curr_lpn].map_status==MAP_REAL){
            clean_flag=1;
        break;
        }
    }

    if(clean_flag==0){
    //      选择LRU位置的脏映射项
        curr_lpn=WRFTL_Head->pre->lpn_num;
        Victim_index=search_table(real_arr,MAP_REAL_MAX_ENTRIES,curr_lpn);
        if(Victim_index==-1){
        printf("can not find LRU pos lpn %d in real_arr\n",curr_lpn);
        assert(0);
        }

    }else{
    //    选择窗口内的干净页映射项
        if(opagemap[curr_lpn].update!=0){
        printf("error opagemap[%d]->update can not be update\n",curr_lpn);
        assert(0);
        }
        Victim_index=search_table(real_arr,MAP_REAL_MAX_ENTRIES,curr_lpn);
        if(Victim_index==-1){
        printf("can not find LRU pos lpn %d in real_arr\n",curr_lpn);
        assert(0);
        }
    }
    return Victim_index;
}